package com.bishe.app.core.utils;


import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

/**
 * Created : 2024/6/29, 12:32
 *
 * @author : jeffrey.hu
 **/
@Component
@Slf4j
public class RedisLockManager {
    final String LUA_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    public RedisLockManager() {
    }

    public boolean lock(String lockKey, String lockValue, int expire, TimeUnit timeUnit) {
        try {
            RedisCallback<Boolean> callback = (connection) -> {
                byte[] keyByte = lockKey.getBytes(StandardCharsets.UTF_8);
                byte[] valueByte = null;
                byte[] valueBytex;
                if (StringUtils.isEmpty(lockValue)) {
                    valueBytex = "1".getBytes(StandardCharsets.UTF_8);
                } else {
                    valueBytex = lockValue.getBytes(StandardCharsets.UTF_8);
                }

                return connection.set(keyByte, valueBytex, Expiration.seconds(timeUnit.toSeconds((long) expire)), RedisStringCommands.SetOption.SET_IF_ABSENT);
            };
            return (Boolean) this.redisTemplate.execute(callback);
        } catch (Exception var6) {
            Exception e = var6;
            log.error("redis lock error.", e);
            return false;
        }
    }

    public String getlock(String lockKey) {
        try {
            RedisCallback<String> callback = (connection) -> {
                byte[] lockValue = connection.get(lockKey.getBytes());
                return null == lockValue ? null : new String(lockValue, StandardCharsets.UTF_8);
            };
            return (String) this.redisTemplate.execute(callback);
        } catch (Exception var3) {
            Exception e = var3;
            log.error("get redis occurred an exception", e);
            return null;
        }
    }

    public boolean releaseLock(String lockKey, String lockValue) {
        RedisCallback<Boolean> callback = (connection) -> {
            byte[] keyByte = lockKey.getBytes(StandardCharsets.UTF_8);
            byte[] valueBytex = null;
            byte[] valueByte;
            if (StringUtils.isEmpty(lockValue)) {
                valueByte = "1".getBytes(StandardCharsets.UTF_8);
            } else {
                valueByte = lockValue.getBytes(StandardCharsets.UTF_8);
            }

            return (Boolean) connection.eval("if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end".getBytes(), ReturnType.BOOLEAN, 1, new byte[][]{keyByte, valueByte});
        };
        return (Boolean) this.redisTemplate.execute(callback);
    }


}

